﻿using System.IO;
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NPOI.HSSF.UserModel;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
using System.Threading;

namespace WebForm
{
    public partial class Form2 : Form
    {
        private List<MountInformation> notFoundIds;
        private BackgroundWorker bw;
        public Form2()
        {
            InitializeComponent();
            webBrowser1.ScriptErrorsSuppressed = false;
            notFoundIds = new List<MountInformation>();
            webBrowser1.Navigate("http://bivouac.com/default.asp");
            bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = true;
            bw.WorkerReportsProgress = true;
            bw.DoWork +=
    new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged +=
                new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync();
            }
        }
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.label2.Text = (e.ProgressPercentage.ToString() + "%");
        }
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var workbook = new HSSFWorkbook();
            var sheet = workbook.CreateSheet("Mountains");
            var headerRow = sheet.CreateRow(0);
            headerRow.CreateCell(0).SetCellValue("Id");
            headerRow.CreateCell(1).SetCellValue("MountName");
            headerRow.CreateCell(2).SetCellValue("AreaName");
            headerRow.CreateCell(3).SetCellValue("Height");
            headerRow.CreateCell(4).SetCellValue("Coordinates");
            headerRow.CreateCell(5).SetCellValue("LineParent");
            headerRow.CreateCell(6).SetCellValue("NTSMapsheet");
            headerRow.CreateCell(7).SetCellValue("KeySaddle");
            headerRow.CreateCell(8).SetCellValue("NameStatus");
            headerRow.CreateCell(9).SetCellValue("FirstAscent");
            for (int i = 0; i < notFoundIds.Count; i++)
            {
                var company = notFoundIds[i];
                var row = sheet.CreateRow(i + 1);
                row.CreateCell(0).SetCellValue(company.Id);
                row.CreateCell(1).SetCellValue(company.MountName);
                row.CreateCell(2).SetCellValue(company.AreaName);
                row.CreateCell(3).SetCellValue(company.Height);
                row.CreateCell(4).SetCellValue(company.Coordinates);
                row.CreateCell(5).SetCellValue(company.LineParent);
                row.CreateCell(6).SetCellValue(company.NTSMapsheet);
                row.CreateCell(7).SetCellValue(company.KeySaddle);
                row.CreateCell(8).SetCellValue(company.NameStatus);
                row.CreateCell(9).SetCellValue(company.FirstAscent);
            }
            using (var file = new FileStream(string.Format("ouput_{0}_{1}.xls", m_txtFrom.Text,m_txtTo.Text), FileMode.Create))
            {
                workbook.Write(file);
                file.Flush();
                file.Close();
            }

            MessageBox.Show("Finish: " + notFoundIds.Count);
            if ((e.Cancelled == true))
            {
                this.label2.Text = "Canceled!";
            }

            else if (!(e.Error == null))
            {
                this.label2.Text = ("Error: " + e.Error.Message);
            }

            else
            {
                this.label2.Text = "Done!";
            }

        }


        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            int index = 0;
            string url;
            int from = int.Parse(m_txtFrom.Text);
            int to = int.Parse(m_txtTo.Text);
            for (int i = from; i <= to; i++)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                url = "http://bivouac.com/MtnPg.asp?MtnId=" + i;
                this.Invoke((Action)delegate() { webBrowser1.Navigate(url); });

                this.BeginInvoke((Action)delegate()
                {
                    label2.Text = "Working......";
                    m_address.Text = url;
                });
                string content = string.Empty;
                webBrowser1.Invoke((Action)delegate()
                {
                    while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
                    {
                        Application.DoEvents();
                    }
                    content = webBrowser1.DocumentText;
                });

                if (!(content.Contains("No record found for") || content.Contains("The webpage cannot be found") || content.Length <= 200))
                {
                    index++;
                    var info = GetMountInformation(content, i);
                    if (info != null)
                    {
                        info.Id = "#" + i;
                        notFoundIds.Add(info);
                    }
                }
                this.BeginInvoke((Action)delegate()
                {
                    label2.Text = "Sleeping......";
                });
                worker.ReportProgress((i * 100) / (to));
                Thread.Sleep(TimeSpan.FromSeconds(Convert.ToDouble(numericUpDown1.Value)));
            }
        }

        private MountInformation GetMountInformation(string document, int id)
        {
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(document);
            var tableNode = doc.DocumentNode.SelectSingleNode("/html/body/table");
            if (tableNode != null)
            {
                MountInformation info = new MountInformation();
                var name = tableNode.SelectSingleNode(".//font[contains(@color,'maroon')]");
                if (name != null)
                {
                    info.MountName = name.InnerText;
                    info.AreaName = GetLine(name);
                }
                var height = tableNode.SelectSingleNode(".//*[contains(text(),'Height')]");
                if (height != null)
                {
                    info.Height = GetHeight(height);
                }
                var cordinates = tableNode.SelectSingleNode(".//*[contains(text(),'Coordinates')]");
                if (cordinates != null)
                {
                    info.Coordinates = GetLine(cordinates);
                }
                var prominence = tableNode.SelectSingleNode(".//*[contains(text(),'Prominence')]");
                if (prominence != null)
                {
                    info.Prominence = GetLine(prominence);
                }
                var lineparent = tableNode.SelectSingleNode(".//*[contains(text(),'Line Parent')]");
                if (lineparent != null)
                {
                    info.LineParent = GetLine(lineparent);
                }
                var keySaddle = tableNode.SelectSingleNode(".//*[contains(text(),'Key Saddle')]");
                if (keySaddle != null)
                {
                    info.KeySaddle = GetLine(keySaddle);
                }

                var ntsMap = tableNode.SelectSingleNode(".//*[contains(text(),'NTS Mapsheet')]");
                if (ntsMap != null)
                {
                    info.NTSMapsheet = GetLine(ntsMap);
                }

                var status = tableNode.SelectSingleNode(".//*[contains(text(),'TitleStatus')]");
                if (status != null)
                {
                    info.NameStatus = GetLine(status);
                }

                var first = tableNode.SelectSingleNode(".//*[contains(text(),'First Ascent')]");
                if (first != null)
                {
                    info.FirstAscent = GetLine(first);
                }
                return info;
            }
            return null;
        }
        private string GetHeight(HtmlNode node)
        {
            StringBuilder builder = new StringBuilder();
            var next = node.NextSibling;
            while (true)
            {
                if (next.Name == "br" || next.InnerText.Contains("Height Report"))
                {
                    break;
                }
                builder.Append(next.InnerText);
                next = next.NextSibling;
            }
            return builder.ToString().TrimStart('?').TrimStart(':').Replace("&nbsp;", " ");
        }
        private string GetLine(HtmlNode node)
        {
            StringBuilder builder = new StringBuilder();
            var next = node.NextSibling;
            if (next == null)
            {
                next = node.ChildNodes.FirstOrDefault(x => !x.Name.Contains("text"));
            }
            while (true)
            {

                if (next == null || next.Name == "br")
                {
                    break;
                }
                builder.Append(next.InnerText);
                next = next.NextSibling;
            }
            return builder.ToString().TrimStart('?').TrimStart(':').Replace("&nbsp;", " ");
        }
    }

    public class MountInformation
    {
        public string MountName { get; set; }
        public string AreaName { get; set; }
        public string Height { get; set; }
        public string Coordinates { get; set; }
        public string Prominence { get; set; }
        public string LineParent { get; set; }
        public string NTSMapsheet { get; set; }
        public string KeySaddle { get; set; }
        public string NameStatus { get; set; }
        public string FirstAscent { get; set; }
        public string Id { get; set; }
    }
}
